package br.com.hs.nfe.common.util;

import br.com.hs.nfe.common.exception.HSCommonException;
import br.com.hs.nfe.common.util.io.CharsetToolkit;
import br.com.hs.nfe.common.util.io.UnicodeInputStream;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Scanner;

/**
 * Classe de auxílio de entrada/saída de arquivos.
 * @author Ranlive Hrysyk
 */
public class IOHelper {

    /**
     * Encoding UTF-8
     */
    public static final String UTF8 = "UTF-8";

    /**
     * Obtém um Scanner de um array de bytes com encoding UTF-8.
     */
    public static Scanner getScanner(byte[] toRead) {
        ByteArrayInputStream inputStream = new ByteArrayInputStream(toRead);
        return new Scanner(inputStream, UTF8);
    }

    /**
     * Obtém um Scanner de um array de bytes.
     */
    public static Scanner getScanner(String toRead) {
        return new Scanner(toRead);
    }

    /**
     * Obtém um Scanner de um arquivo.
     */
    public static Scanner getScannerUTF8(File file) throws Exception {
        Charset fileEncoding = CharsetToolkit.guessEncoding(file, 4096);
        if (!Charset.forName(UTF8).equals(fileEncoding)) {
            return null;
        }
        InputStream in = getInputStreamUTF8(file);
        return new Scanner(in, UTF8);
    }

    /**
     * Obtém um Scanner de um InputStream com UTF-8.
     */
    public static InputStream getInputStreamUTF8(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        UnicodeInputStream uin = new UnicodeInputStream(fis, UTF8);
        uin.getEncoding();
        return uin;
    }

    /**
     * Grava um arquivo no disco.
     * @param path Caminho e nome do arquivo
     * @param conteudo Conteúdo do arquivo
     */
    public static void writeFile(String path, String conteudo) throws HSCommonException {
        try {
            FileWriter fileWriter = null;
            try {
                fileWriter = new FileWriter(new File(path));
                fileWriter.write(conteudo);
            } finally {
                if (fileWriter != null) {
                    fileWriter.flush();
                    fileWriter.close();
                }
            }
        } catch (IOException e) {
            throw new HSCommonException(e.getMessage(), e);
        }
    }

    /**
     * Lê um arquivo do disco.
     * @param path Caminho e nome do arquivo.
     * @return Conteúdo do arquivo.
     */
    public static String readFile(String path) throws HSCommonException {
        try {
            BufferedReader bufferedReader = null;
            try {
                bufferedReader = new BufferedReader(new FileReader(new File(path)));

                StringBuilder builder = new StringBuilder();
                int c;
                while ((c = bufferedReader.read()) != -1) {
                    builder.append((char) c);
                }
                String str = builder.toString();
                return str;
            } finally {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            }
        } catch (IOException e) {
            throw new HSCommonException(e.getMessage(), e);
        }
    }

    /**
     * Lê um arquivo do disco sem encoding UTF-8.
     * @param path Caminho e nome do arquivo.
     * @return Conteúdo do arquivo.
     */
    public static String readFileSemBom(String path) throws HSCommonException {
        return readFileSemBom(new File(path));
    }

    /**
     * Lê um arquivo do disco sem encoding UTF-8.
     * @param path Caminho e nome do arquivo.
     * @return Conteúdo do arquivo.
     */
    public static String readFileSemBom(File file) throws HSCommonException {
        try {
            InputStream inputStream = null;
            String conteudo = null;
            try {
                inputStream = getInputStreamUTF8(file);
                int length = (int) file.length();
                byte[] buffer = new byte[length];
                inputStream.read(buffer);
                if ((buffer[(length - 3)] == 0) && (buffer[(length - 2)] == 0) && (buffer[(length - 1)] == 0)) {
                    length -= 3;
                }
                conteudo = new String(buffer, 0, length, UTF8);
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
            }
            return conteudo;
        } catch (IOException e) {
            throw new HSCommonException(e.getMessage(), e);
        }
    }

    /**
     * Verifica se um arquivo existe e pode ser acessado.
     * @param path Caminho e nome do arquivo.
     * @param create Se não existir criar.
     * @return Retorna true se existir.
     */
    public static boolean verifyFile(String path, boolean create) {
        File file = new File(path);

        if (file.exists()) {
            if ((!file.canWrite()) || (!file.canRead())) {
                return false;
            }
        } else if (create) {
            return file.mkdirs();
        }
        return true;
    }

    /**
     * Exclui um arquivo do disco.
     * @param path Caminho e nome do arquivo.
     * @return Retorna true se obteve êxito.
     */
    public static boolean delete(String path) {
        File file = new File(path);

        if (file.exists()) {
            if ((!file.canWrite()) || (!file.canRead())) {
                return false;
            }
        } else {
            return false;
        }
        return file.delete();
    }
}
